unit ExperimentThread;

interface

uses  Classes,ComCtrls,ExperimentStruct, ScienceFun, Math;


type
 TRandFunction = function:double of object;
 TFreqArray = array of integer;
 TFinalCallback = procedure(expRec: TExperimentRecord) of object;
 TPDFFunction = function(a,x: double): double;
 TCDFFunction = TPDFFunction;

 function NeumanRand: double; external  'RandomFunctions.dll'
 function InverseRand: double; external 'RandomFunctions.dll'
 procedure InitRandomFunctions(pfun: TPDFFunction; cFun: TCDFFunction);external 'RandomFunctions.dll'
 procedure SetParameters(paramA, right, maxPDF: double; valuesCount: integer);external 'RandomFunctions.dll'


type
 TExpThread = class(TThread)
   progressBar_: TProgressBar;
  procedure InitExperiment(var expRec: TExperimentRecord ;
                           finalCallback: TFinalCallback;
                           progressBar: TProgressBar;
                           useNeuman: boolean;
                           useInverse: boolean
                           );
   procedure Execute; override;
  public
   randFun_: TRandFunction;
   finalCallback_: TFinalCallback;
  private
   expRec_: TExperimentRecord;
   useN_: boolean;
   useI_: boolean;
   runningProgress: integer;
   totalIter: int64;
   maxFunVal: double;
  function MaxMaxwelBoltzVal:double;
  procedure Progress;
  procedure Loop;
  procedure Final;
 end;

implementation

uses StrUtils;

procedure TExpThread.Loop;
begin

end;

procedure TExpThread.Execute;
var
 i: int64;
 max: double;
 xOverFun, intervalsLen: double;
 arr: TFreqArray;
 addToNext: integer;
 timeToShow: integer;
 meanSum, varSum: double;
begin
 inherited;

 totalIter:=0;
 if (useN_) then
  begin
   totalIter:=totalIter + expRec_.experimentCount_;
   addToNext := expRec_.experimentCount_;
  end;
   if (useI_) then
    totalIter:=totalIter  + expRec_.experimentCount_;
 SetLength(arr, expRec_.valuesCount_);
 i:=0;
 intervalsLen:=expRec_.rightValue_/expRec_.valuesCount_;
 runningProgress:=0;
 timeToShow:=  0;
 if(useN_) then
  begin
   while(i<expRec_.experimentCount_) and (not Terminated) do
    begin
     xOverFun:=NeumanRand;
     Inc(arr[trunc(xOverFun/intervalsLen)]);
     runningProgress:=trunc(100*i/(totalIter));
     if(timeToShow = 0) then
     begin
      timeToShow:=  50;
      Synchronize(Progress);
     end;
     Dec(timeToShow);
     Inc(i);
    end;
  max:=arr[0];
  i:=1;
  timeToShow:= 0;

   while(i<expRec_.valuesCount_) and (not Terminated) do
    begin
     if(max<arr[i]) then
      max:=arr[i];
     Inc(i);
    end;
  expRec_.neumanExp_:= TExperiment.Create('Neuman', 0, 0, arr, expRec_.valuesCount_, maxFunVal/max);
  i:=0;
  meanSum:=0;
  while(i<expRec_.valuesCount_) and (not Terminated) do
  begin
   meanSum:=meanSum + arr[i]*intervalsLen*i/expRec_.experimentCount_;
   varSum:=varSum + arr[i]*Power(intervalsLen*i,2)/expRec_.experimentCount_;
   Inc(i);
  end;
  varSum:=varSum-meanSum*meanSum;
  expRec_.neumanExp_.mean_:=meanSum;
  expRec_.neumanExp_.variance_:=varSum;
 end;
 if(useI_) then
  begin
   while(i<expRec_.experimentCount_) and (not Terminated) do
    begin
     xOverFun:=InverseRand;
     Inc(arr[trunc(xOverFun/intervalsLen)]);
     runningProgress:=trunc(100*(i+ addToNext)/(totalIter));
     if(timeToShow = 0) then
     begin
      timeToShow:= 50;
      Synchronize(Progress);
     end;
     Dec(timeToShow);
     Inc(i);
    end;
   max:=arr[0];
   i:=1;
    while(i<expRec_.valuesCount_) and (not Terminated) do
     begin
      if(max<arr[i]) then
       max:=arr[i];
      Inc(i);
     end;
   expRec_.inverseExp_:= TExperiment.Create('Inverse', 0, 0, arr, expRec_.valuesCount_, maxFunVal/max);
  i:=0;
  meanSum:=0;
  varSum:=0;
  while(i<expRec_.valuesCount_) and (not Terminated) do
  begin
   meanSum:=meanSum + arr[i]*intervalsLen*i/expRec_.experimentCount_;
   varSum:=varSum + arr[i]*Power(intervalsLen*i,2)/expRec_.experimentCount_;
   Inc(i);
  end;
  varSum:=varSum-meanSum*meanSum;
  expRec_.inverseExp_.mean_:=meanSum;
  expRec_.inverseExp_.variance_:=varSum;

 end;
 SetLength(arr, 0);
 runningProgress:=100;
 Synchronize(Progress);
 if(not Terminated) then
    Synchronize(Final)
 else
  begin
   if(useN_) then
    expRec_.neumanExp_.Destroy;
   if(useI_) then
    expRec_.inverseExp_.Destroy;
  end;
end;

procedure TExpThread.Final;
begin
 finalCallback_(expRec_);
end;

procedure TExpThread.Progress;
begin
 progressBar_.Position:=runningProgress;
end;

procedure TExpThread.InitExperiment(var expRec: TExperimentRecord ;
                                        finalCallback: TFinalCallback;
                                        progressBar: TProgressBar;
                                        useNeuman: boolean;
                                        useInverse: boolean);

begin
 expRec_:=expRec;
 expRec_.neumanExp_:=nil;
 expRec_.inverseExp_:=nil;
 finalCallback_:= finalCallback;
 progressBar_:=progressBar;
 useN_:=useNeuman;
 useI_:=useInverse;
 maxFunVal:=MaxMaxwelBoltzVal;
 InitRandomFunctions(MaxBoltzDistr, MaxBoltzDistrCDF);
 SetParameters(expRec_.a_, expRec_.rightValue_, maxFunVal, expRec_.valuesCount_);
end;

function TExpThread.MaxMaxwelBoltzVal: double;
var x, prev, y :double;
begin
 x:=0.001;
 prev:=MaxBoltzDistr(expRec_.a_,x);
 while (true) do
 begin
  x:=x+0.001;
  y:=MaxBoltzDistr(expRec_.a_,x);
  if y<prev then
   break
  else
   prev:=y;
 end;
 result:=y;
end;

end.
